﻿using System;
using System.Collections.Generic;
using System.Configuration;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace Msdn5.Framework
{
    /// <summary>
    /// 配置文件相关
    /// </summary>
    public static class ConfigHelper
    {
        #region 配置文件
        /// <summary>
        /// 基目录
        /// </summary>
        public static string BaseDir { get; set; } = AppDomain.CurrentDomain.BaseDirectory;

        /// <summary>
        /// 获取运行目录下的所有文件
        /// 如果不填写则获取当前运行目录
        /// </summary>
        /// <param name="path">子目录名称</param>
        /// <returns></returns>
        public static string[] GetFiles(this string path)
        {
            if (path.NotNullOrEmpty())
            {
                path = $"{BaseDir}{path}\\";
            }
            else
            {
                path = BaseDir;
            }
            return Directory.GetFiles(path);
        }

        /// <summary>
        /// 读取文件内容(不占用文件)
        /// </summary>
        /// <param name="filePath">文件绝对路径</param>
        /// <param name="succCallBack">读取成功的回调函数</param>
        /// <param name="errCallBack">读取失败的回调函数</param>
        public static void ReaderFileBytes(this string filePath, Action<byte[]> succCallBack = null, Action<Exception> errCallBack = null)
        {
            try
            {
                var info = new FileInfo(filePath);
                if (info.Exists)
                {
                    using (var fs = info.Open(FileMode.Open, FileAccess.Read, FileShare.Read))
                    {
                        if (fs.CanRead)
                        {
                            var buffer = new byte[fs.Length];
                            fs.Read(buffer, 0, buffer.Length);
                            succCallBack?.Invoke(buffer);
                        }
                        else
                        {
                            errCallBack?.Invoke(new Exception("[文件读取失败]:无法读取当前文件流!"));
                        }
                    }
                }
                else
                {
                    errCallBack?.Invoke(new Exception("[文件读取失败]:当前指定的文件不存在!"));
                }
            }
            catch (Exception ex)
            {
                errCallBack?.Invoke(new Exception($"[文件读取异常]: {ex.Message}"));
            }
        }
        /// <summary>
        /// 写入文件内容(不占用文件)
        /// </summary>
        /// <param name="filePath">文件绝对路径</param>
        /// <param name="buffer">要写入的字节内容</param>
        /// <param name="mode">覆盖还是添加,默认为覆盖</param>
        /// <param name="callBack">回调函数,如果为Null表示写入成功,否则为异常信息</param>
        public static void WriteFileBytes(this string filePath, byte[] buffer, FileMode mode = FileMode.Create, Action<Exception> callBack = null)
        {
            try
            {
                if (buffer == null)
                {
                    callBack?.Invoke(new ArgumentNullException("要写入的文件内容不能为Null"));

                }
                var acc = mode == FileMode.Append ? FileAccess.Write : FileAccess.ReadWrite;
                using (var fs = new FileStream(filePath, mode, acc, FileShare.ReadWrite))
                {
                    if (fs.CanWrite)
                    {
                        fs.Write(buffer, 0, buffer.Length);
                        callBack?.Invoke(null);
                    }
                    else
                    {
                        callBack?.Invoke(new Exception("[文件写入取失败]:无法写入当前文件流!"));
                    }
                }

            }
            catch (Exception ex)
            {
                callBack?.Invoke(new Exception($"[文件写入异常]: {ex.Message}"));
            }
        }

        /// <summary>
        /// 写入文件
        /// 如果文件名携带路径,则会创建子文件夹
        /// </summary>
        /// <param name="text">写入内容</param>
        /// <param name="fname">文件名(带后缀),如果文件名携带路径,则会创建子文件夹</param>
        /// <param name="mode">默认写入为覆盖写入</param>
        /// <param name="directoryPath">保存的路径,默认为JsonFile,如果为空则为根目录</param>
        /// <param name="callback">异常时携带异常信息</param>
        public static void WriteFile(this string text, string fname, FileMode mode = FileMode.Create, string directoryPath = "JsonFile", Action<Exception> callback = null)
        {
            try
            {
                if (directoryPath.NotNullOrEmpty())
                {
                    directoryPath = $"{BaseDir}{directoryPath}\\";
                }
                else
                {
                    directoryPath = $"{BaseDir}";
                }
                string fp = $"{directoryPath}{fname}";
                FileInfo fileInfo = new FileInfo(fp);
                if (!fileInfo.Directory.Exists)
                {
                    fileInfo.Directory.Create();
                }
                WriteFileBytes(fp, Encoding.UTF8.GetBytes(text), mode, callback);
            }
            catch (Exception ex)
            {
                callback?.Invoke(ex);
            }

        }

        /// <summary>
        /// 读取文件内容
        /// 如果填写绝对路径则读取绝对路径文件
        /// 如果填写相对路径则读取运行路径下的DirectoryPath的文件
        /// </summary>
        /// <param name="filePath">文件绝对路径</param>
        /// <param name="succCallBack">读取成功的回调函数</param>
        /// <param name="errCallBack">读取失败的回调函数</param>
        /// <param name="directoryPath">读取的子路径,默认为JsonFile</param>
        public static void ReaderFile(this string filePath, Action<string> succCallBack = null, Action<Exception> errCallBack = null, string directoryPath = "JsonFile")
        {
            //如果不存在盘符信息则认为是读取运行目录下的文件
            if (filePath.IndexOf(":") == -1)
            { 
                if (directoryPath.NotNullOrEmpty())
                {
                     
                    filePath = $"{BaseDir}{directoryPath}\\{filePath}";
                }
                else
                {
                    filePath = $"{BaseDir}{filePath}";
                }
            } 
            if (File.Exists(filePath))
            {
                using (StreamReader reader = new StreamReader(File.Open(filePath, FileMode.Open, FileAccess.ReadWrite, FileShare.ReadWrite), Encoding.UTF8))
                {
                    succCallBack?.Invoke(reader.ReadToEnd());
                }
            }
            else
            {
                errCallBack?.Invoke(new Exception($"[文件读取失败]:当前文件[{filePath}]不存在!"));
            }
        }
#if NET45
        /// <summary>
        /// 获取ConnectionString
        /// </summary>
        /// <param name="key">配置文件的Key</param>
        /// <returns>返回配置项</returns>
        public static string GetConnectionString(this string key)
        {
            return GetKey(key, 1);
        }

        /// <summary>
        /// 获取AppSetting
        /// </summary>
        /// <param name="key">配置文件的Key</param>
        /// <returns>返回配置项</returns>
        public static string GetAppSetting(this string key)
        {
            return GetKey(key);
        }
        /// <summary>
        /// 获取AppSetting的某个字段并且转换为bool值
        /// </summary>
        /// <param name="key">配置文件的Key</param>
        /// <returns>是否为bool</returns>
        public static bool GetAppSettingToBool(this string key)
        {
            string keystr = GetKey(key);
            return keystr.TryToBool();
        }
        /// <summary>
        /// 获取GetConnectionString的某个字段并且转换为bool值
        /// </summary>
        /// <param name="key">配置文件的Key</param>
        /// <returns>是否为bool</returns>
        public static bool GetConnectionStringToBool(this string key)
        {
            string keystr = GetKey(key, 1);
            return keystr.TryToBool();
        }

        /// <summary>
        /// 获取AppSetting的某个字段并且转换为Int值
        /// </summary>
        /// <param name="key">配置文件的Key</param>
        /// <returns>转换后的int值</returns>
        public static int GetAppSettingToInt(this string key)
        {
            string keystr = GetKey(key);
            return keystr.TryToInt();
        }
        /// <summary>
        /// 获取GetConnectionString的某个字段并且转换为bool值
        /// </summary>
        /// <param name="key">配置文件的Key</param>
        /// <returns>是否为bool</returns>
        public static int GetConnectionStringToInt(this string key)
        {
            string keystr = GetKey(key, 1);
            return keystr.TryToInt();
        }

        /// <summary>
        /// 获取配置文件的key
        /// 默认获取AppSettings
        /// </summary>
        /// <param name="key">字符串key</param>
        /// <param name="type">0获取AppSettings 其他非0获取ConnectionStrings</param>
        /// <returns></returns>
        public static string GetKey(this string key, int type = 0)
        {
            return type == 0 ? ConfigurationManager.AppSettings[key]?.ToString() : ConfigurationManager.ConnectionStrings[key]?.ConnectionString;
        }

#endif
        #endregion
    }
}
